package com.ywk.base.javaBase.reflection;

import com.ywk.base.javaBase.reflection.ann.ClassTest;
import com.ywk.base.javaBase.reflection.ann.FieldTest;

import java.lang.annotation.Annotation;
import java.lang.reflect.*;
import java.util.Map;

/**
 * @Author zbh
 * @Date 2023/4/20
 */
public class ReflectionDemo {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException, IllegalAccessException {
        /**
         * 通过反射获取类或者属性的注解并且得到它们的信息
         */
        //通过反射获取类
        Class<?> studentsClass = Class.forName("com.ywk.base.javaBase.reflection.Students");
        System.out.println("aClass= "+studentsClass);
        //通过getAnnotations()得到所有的注解
        Annotation[] annotations = studentsClass.getAnnotations();
        //for循环输出注解所有的信息
        for (Annotation annotation:annotations) {
            System.out.println(annotation);//@com.Test.ClassTest(ClassName=StudentsTableTest)
            //通过annotationType()方法得到类名以及类型
            Class<? extends Annotation> annotationType = annotation.annotationType();
            System.out.println(annotationType);//interface com.Test.ClassTest
            //通过getName得到全类名
            String annotationName = annotationType.getName();
            System.out.println(annotationName);//com.Test.ClassTest
            Class anClass = Class.forName(annotationName);
            //获取这个注解里面所有的属性
            Field[] declaredFields = anClass.getDeclaredFields();
            System.out.println("declaredFields的长度为: "+declaredFields.length);
            for (Field field:declaredFields) {
                System.out.println("field= "+field);
            }
            //获取这个注解里面所有的方法
            Method[] methods = anClass.getMethods();
            for (Method met: methods) {
                System.out.println("met= "+met);//public abstract java.lang.String com.Test.ClassTest.value()
                System.out.println("方法名称"+met.getName());//ClassName
                System.out.println(met.getModifiers());//1025
                System.out.println("配合Modifier的ToString方法将对应的int类型转换为修饰符:"+ Modifier.toString(met.getModifiers()));//public abstract
            }
        }

        System.out.println("\n====================================\n");
        //通过getAnnotation()方法传入指定的注解名字得到此注解;(获取students类的ClassTest注解)
        ClassTest tableTestAnnotation = studentsClass.getAnnotation(ClassTest.class);
        //得到注解所有的信息
        System.out.println(tableTestAnnotation);//@com.Test.ClassTest(value=StudentsTableTest, why=为什么)
        //得到注解 ClassName 的值
        System.out.println(tableTestAnnotation.ClassName());//StudentsTableTest
        //修改类注解属性值
        InvocationHandler inv = Proxy.getInvocationHandler(tableTestAnnotation);
        Field classValue = inv.getClass().getDeclaredField("memberValues");
        classValue.setAccessible(true);
        Map<String, Object> classMemberValues = (Map<String, Object>) classValue.get(inv);
        String className = classMemberValues.get("ClassName").toString();
        className="Students2";
        classMemberValues.put("ClassName",className);
        /**
         * 获取属性上的注解并且修改注解中的值
         */
        //获取students类的name字段(获取students的name属性)
        Field name = studentsClass.getDeclaredField("name");
        //获取字段name上的FieldTest注解实例
        FieldTest nameField = name.getAnnotation(FieldTest.class);
        //获取FieldTest注解中columnName的值
        System.out.println(nameField.columnName());//Cname
        //获取 nameField 这个代理实例所持有的 InvocationHandler
        InvocationHandler invocationHandler = Proxy.getInvocationHandler(nameField);
        // 获取 AnnotationInvocationHandler 的 memberValues 字段(此写法唯一)
        Field fieldValue = invocationHandler.getClass().getDeclaredField("memberValues");
        System.out.println("value="+fieldValue);//private final java.util.Map sun.reflect.annotation.AnnotationInvocationHandler.memberValues
        //如果为私有则打开权限
        fieldValue.setAccessible(true);
        //获取memberValues
        Map<String, Object> memberValues = (Map<String, Object>) fieldValue.get(invocationHandler);
        //获取此注解中 columnName 的值
        String columnName = (String) memberValues.get("columnName");
        System.out.println("改变前columnName的值：" + columnName);
        columnName = "Jack";
        //修改 columnName 属性值不修改type的值
        memberValues.put("columnName", columnName);
        //获取 columnName 的值
        System.out.println("改变后columnName的值：" + memberValues.get("columnName"));
    }


}
